﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.IO;
using System.Xml;
using System.Globalization;
using RouterControl.IO;

namespace RouterControl.Whs.Properties
{
	public sealed class ApplicationFolderSettingsProvider : SettingsProvider
	{
		private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(ApplicationFolderSettingsProvider));
		
		public override string ApplicationName
		{
			get;
			set;
		}

		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			if (string.IsNullOrEmpty(name))
				name = GetType().FullName;

			base.Initialize(name, config);
		}

		private static FileInfo GetConfigFileByContext(SettingsContext context)
		{
            // handle design time loading of settings
            if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            {
                var fi = new FileInfo(Path.Combine(Path.GetTempPath(), "DesignTimeConfig.tmp"));

                if (fi.Exists)
                {
                    fi.Delete();

                    fi.Refresh();
                }

                return fi;
            }

		    // determine settings file
			var groupName = (string)context["GroupName"];
			var key = context["SettingsKey"] as string;

			var sectionName = groupName;

			if (!string.IsNullOrEmpty(key))
			{
				sectionName = string.Format("{0}.{1}", sectionName, key);
			}

			return new FileInfo(ApplicationFolders.Instance.DuplicatedDir.FullName + "\\" + sectionName + ".config");
		}

		public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
		{
			var fi = GetConfigFileByContext(context);

			if (_log.IsDebugEnabled)
				_log.Debug("Loading settings file: " + fi.FullName + " ...");

			// load xml
			try
			{
				var xml = new XmlDocument();
				var noSettings = !fi.Exists;
	
				if (!noSettings)
				{
					using (var s = fi.OpenText())
					{
						xml.Load(s);
					}
				}
	
				// gather values
				var ret = new SettingsPropertyValueCollection();
	
				foreach (SettingsProperty p in collection)
				{
					var spv = new SettingsPropertyValue(p);
	
					spv.IsDirty = false;
	
					if (noSettings)
						spv.SerializedValue = p.DefaultValue ?? string.Empty;
					else
					{
						var elem = xml.SelectSingleNode("//" + p.Name) as XmlElement;
	
						if (elem == null)
							spv.SerializedValue = (p.DefaultValue == null ? string.Empty : p.DefaultValue.ToString());
						else
							spv.SerializedValue = elem.InnerText;
					}
	
					ret.Add(spv);

					if (_log.IsDebugEnabled)
						_log.DebugFormat("  {0} = {1}", spv.Name, spv.SerializedValue as string);
				}
	
				// finalize
				if (noSettings)
					_log.Info("Loaded default settings for file: " + fi.FullName);
				else
					_log.Info("Loaded settings file: " + fi.FullName);
	
				return ret;
			}
			catch (Exception e)
			{
				_log.Fatal("Failed to load settings file: " + fi.FullName, e);

				throw;
			}
		}

		public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
		{
			var fi = GetConfigFileByContext(context);

			if (_log.IsDebugEnabled)
				_log.Debug("Saving settings file: " + fi.FullName + " ...");

			try
			{
				using (var tw = fi.CreateText())
				{
					using (var xw = new XmlTextWriter(tw))
					{
					    xw.Formatting = Formatting.Indented;

						xw.WriteStartDocument();
						xw.WriteStartElement("settings");
						{
							xw.WriteAttributeString("version", RouterControlVersion.VersionId.ToString());
	
							foreach (SettingsPropertyValue spv in collection)
							{
								var val = (spv.SerializedValue == null ? string.Empty : spv.SerializedValue.ToString());

								xw.WriteElementString(spv.Name, val);

								if (_log.IsDebugEnabled)
									_log.DebugFormat("  {0} = {1}", spv.Name, val);
							}
						}
						xw.WriteEndElement();
						xw.WriteEndDocument();
					}
				}
	
				// done
				_log.Info("Saved settings file: " + fi.FullName);
			}
			catch (Exception e)
			{
				_log.Fatal("Failed to save settings file: " + fi.FullName, e);

				throw;
			}
		}
	}
}
